/* 先把文件中的数据存储到数组中
 *      *第一次进入显示操作方法
 * 主界面：
 *      预约出入校：
 *          ·新建条目，填写除了实际出入时间外的所有字段
 *              *检测输入合法性 done
 *      登记入校
 *          ·显示已预约的所有条目（不显示已完成的条目）
 *          ·输入条目序号，填写出入校时间。
 *              *提供不修改返回的功能，防止手滑 done
 *              *检测时间格式合法性 done
 *      登记出校
 *          ·和入校类似，只是修改的字段变成了出校
 *      已完成
 *          ·展示已经填写过实际出入校时间的已完成记录
 *              *提供再次修改字段的功能
 *      保存并退出
 *          · 清空原来的文本文件，填充数组内容到里面。
 *      摸鱼
 *          *玩贪吃蛇
 */

#include <iostream>
#include <iomanip>
#include <windows.h>
#include <string>
#include <vector>
#include <fstream>
#include "snake.cpp"
using namespace std;

typedef struct
{
    string name;                     // 姓名
    bool sex;                        // 0->female 1->male
    string phoneNumber;              // 手机号码
    string idNumber;                 // 身份证号
    string organization;             // 单位信息
    string carNumber;                // 车牌号
    string reason;                   // 进校理由
    string warrantor;                // 担保人
    string warrantorPhoneNumber;     // 担保人手机号码
    string healthQRCodeColor;        // 健康码颜色
    bool visitedRiskyRegionIn14Days; // 是否十四天内去过疫区
    bool caughtCold;                 // 是否咳嗽发热
    string estimatedEnterTime;       // 申请进入时间
    string estimatedLeaveTime;       // 申请离开时间
    string actualEnterTime;          // 实际进入时间
    string actualLeaveTime;          // 实际离开时间
    bool expired;                    // 标记是否已完成
} Record;

//----------------全局变量-------------------

vector<Record> records;
string path = "./"; // 数据文件存储的相对路径
string database_name = "record.txt";
HANDLE hOut;
COORD pos;
//-----------------------------------------

void gotoxy(short x, short y)
{
    hOut = GetStdHandle(STD_OUTPUT_HANDLE); //获取句柄
    pos = {x, y};
    SetConsoleCursorPosition(hOut, pos); //移动光标
}

void HideCursor() //隐藏光标
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(handle, &CursorInfo); //获取控制台光标信息
    CursorInfo.bVisible = false;               //隐藏控制台光标
    SetConsoleCursorInfo(handle, &CursorInfo); //设置控制台光标状态
}

void ShowCursor() //展示光标
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(handle, &CursorInfo); //获取控制台光标信息
    CursorInfo.bVisible = true;                //隐藏控制台光标
    SetConsoleCursorInfo(handle, &CursorInfo); //设置控制台光标状态
}

void PrintTitle() //打印主界面
{
    int width = 15;
    cout << setw(4)
         << "No."
         << setw(4)
         << "姓名"
         << setw(6)
         << "性别"
         << setw(11)
         << "手机号码"
         << setw(18)
         << "身份证号"
         << setw(20)
         << "单位信息"
         << setw(10)
         << "车牌号"
         << setw(20)
         << "进校理由"
         << setw(4)
         << "担保人"
         << setw(11)
         << "担保人手机号"
         << setw(4)
         << "健康码"
         << setw(4)
         << "高危区"
         << setw(4)
         << "咳嗽发热"
         << setw(20)
         << "申请进入时间"
         << setw(20)
         << "申请离开时间"
         << setw(20)
         << "实际进入时间"
         << setw(20)
         << "实际离开时间"
         << endl;
}

string Boolean2Shifou(boolean b) //把bool值转化为是否
{
    if (b)
    {
        return "是";
    }
    else
    {
        return "否";
    }
}

string Boolean2Sex(boolean b) //把bool值转化为性别
{
    if (b)
    {
        return "男";
    }
    else
    {
        return "女";
    }
}

void PrintRecord(Record me) //打印一条记录
{
    int width = 10;
    cout << me.name
         << setw(6)
         << Boolean2Sex(me.sex)
         << setw(11)
         << me.phoneNumber
         << setw(18)
         << me.idNumber
         << setw(20)
         << me.organization
         << setw(10)
         << me.carNumber
         << setw(20)
         << me.reason
         << setw(4)
         << me.warrantor
         << setw(11)
         << me.warrantorPhoneNumber
         << setw(4)
         << me.healthQRCodeColor
         << setw(4)
         << Boolean2Shifou(me.visitedRiskyRegionIn14Days)
         << setw(4)
         << Boolean2Shifou(me.caughtCold)
         << setw(20)
         << me.estimatedEnterTime
         << setw(20)
         << me.estimatedLeaveTime
         << setw(20)
         << me.actualEnterTime
         << setw(20)
         << me.actualLeaveTime
         << endl;
}

boolean DetectExistingData() //检测是否存在已有数据
{
    ifstream file;
    file.open(path + database_name);
    boolean flag = file.good();
    file.close();
    return flag;
}

void CreateDatabase()
{
    ofstream ofile;
    ofile.open(path + database_name);
    ofile.close();
}

void SaveRecords()
{
    ofstream ofile;
    ofile.open(path + database_name);
    ofile.clear();
    for (int i = 0; i < (int)records.size(); i++)
    {
        Record me = records[i];
        ofile << me.name
              << " "
              << me.sex
              << " "
              << me.phoneNumber
              << " "
              << me.idNumber
              << " "
              << me.organization
              << " "
              << me.carNumber
              << " "
              << me.reason
              << " "
              << me.warrantor
              << " "
              << me.warrantorPhoneNumber
              << " "
              << me.healthQRCodeColor
              << " "
              << me.visitedRiskyRegionIn14Days
              << " "
              << me.caughtCold
              << " "
              << me.estimatedEnterTime
              << " "
              << me.estimatedLeaveTime
              << " "
              << me.actualEnterTime
              << " "
              << me.actualLeaveTime
              << " "
              << me.expired
              << endl;
    }
    ofile.close();
}

void ReadRecords()
{
    ifstream ifile;
    ifile.open(path + database_name);
    while (!ifile.eof())
    {
        Record me;
        ifile >> me.name >> me.sex >> me.phoneNumber >> me.idNumber >> me.organization >> me.carNumber >> me.reason >> me.warrantor >> me.warrantorPhoneNumber >> me.healthQRCodeColor >> me.visitedRiskyRegionIn14Days >> me.caughtCold >> me.estimatedEnterTime >> me.estimatedLeaveTime >> me.actualEnterTime >> me.actualLeaveTime >> me.expired;
        records.push_back(me);
    }
    cout << "LOADED RECORDS " << (int)records.size() << endl;
    ifile.close();
}

void PrintAllActiveRecords()
{
    PrintTitle();
    for (int i = 0; i < (int)records.size(); i++)
    {
        if (!records[i].expired)
        {
            cout << setw(4) << i;
            PrintRecord(records[i]);
        }
    }
}

void PrintAllFinishedRecords()
{
    system("cls");
    PrintTitle();
    for (int i = 0; i < (int)records.size(); i++)
    {
        if (records[i].expired)
        {
            cout << setw(4) << i;
            PrintRecord(records[i]);
        }
    }
}

string InputTime()
{
    // 由用户输入返回"2020-20-20_20:20"格式的时间
    string FullTime = "";
    int tmp;
    int month;
    int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    cout << "年：" << endl;
    while (true)
    {
        cin >> tmp;
        if (tmp < 2021 || tmp > 2022)
        {
            cout << "请重新输入，年份只能是2021或2022" << endl;
        }
        else
        {
            break;
        }
    }
    FullTime += (to_string(tmp) + "-");
    cout << "月：" << endl;
    while (true)
    {
        cin >> month;
        if (tmp < 1 || month > 12)
        {
            cout << "请检查输入月份正确性";
        }
        else
        {
            break;
        }
    }
    if (month < 10)
    {
        FullTime += ("0" + to_string(month) + "-");
    }
    else
    {
        FullTime += (to_string(month) + "-");
    }
    cout << "日：" << endl;
    while (true)
    {
        cin >> tmp;
        if (tmp < 1 || tmp > days[month])
        {
            cout << "请检查输入日期正确性";
        }
        else
        {
            break;
        }
    }
    if (tmp < 10)
    {
        FullTime += ("0" + to_string(tmp) + "_");
    }
    else
    {
        FullTime += (to_string(tmp) + "_");
    }
    cout << "小时(24h制)：" << endl;
    while (true)
    {
        cin >> tmp;
        if (tmp < 0 || tmp > 23)
        {
            cout << "请检查输入小时正确性";
        }
        else
        {
            break;
        }
    }
    if (tmp < 10)
    {
        FullTime += ("0" + to_string(tmp) + ":");
    }
    else
    {
        FullTime += (to_string(tmp) + ":");
    }
    cout << "分钟" << endl;
    while (true)
    {
        cin >> tmp;
        if (tmp < 0 || tmp > 60)
        {
            cout << "请检查输入分钟正确性";
        }
        else
        {
            break;
        }
    }
    if (tmp < 10)
    {
        FullTime += ("0" + to_string(tmp));
    }
    else
    {
        FullTime += to_string(tmp);
    }
    return FullTime;
}

int ExtractYear(string time)
{
    for (int i = 0; i < time.length(); i++)
    {
        if (time[i] == '-')
        {
            return stoi(time.substr(0, i));
        }
    }
}

int ExtractMonth(string time)
{
    int first = -1;
    for (int i = 0; i < time.length(); i++)
    {
        if (time[i] == '-')
        {
            if (first == -1)
            {
                first = i;
            }
            else
            {
                return stoi(time.substr(first - 1, i - first));
            }
        }
    }
}

int ExtractDay(string time)
{
    int first = -1;
    int second = -1;
    for (int i = 0; i < time.length(); i++)
    {
        if (time[i] == '-')
        {
            if (first == -1)
            {
                first = i;
            }
            else if (second == -1)
            {
                second = i;
            }
        }
        if (time[i] == '_')
        {
            return stoi(time.substr(second, i));
        }
    }
    return 0;
}

int ExtractHour(string time)
{
    int underline = -1;
    int two = -1;
    for (int i = 0; i < time.length(); i++)
    {
        if (time[i] == '_')
        {
            return stoi(time.substr(underline, i));
            break;
        }
    }
    for (int i = 0; i < time.length(); i++)
    {
        if (time[i] == ':')
        {
            return stoi(time.substr(two, i));
            break;
        }
    }
    return stoi(time.substr(underline, two));
}

int ExtractMinute(string time)
{
    int underline = -1;
    int two = -1;
    for (int i = 0; i < time.length(); i++)
    {
        if (time[i] == '_')
        {
            return stoi(time.substr(underline, i));
            break;
        }
    }
    for (int i = 0; i < time.length(); i++)
    {
        if (time[i] == ':')
        {
            return stoi(time.substr(two, i));
            break;
        }
    }
    return stoi(time.substr(two, time.length() - two));
}

bool CompareTime(string time1, string time2)
{
    if (time1.compare(time2) < 0)
    {
        return true;
    }
    return false;
}

bool ValidateIDNumber(string idnumber)
{
    if (idnumber.length() == 18)
    {
        int idnumbers[18];
        int xishu[18] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
        int validation[11] = {1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2};
        int xishusum;
        for (int i = 0; i < 18; i++)
        {
            if (idnumber[i] != 'X' && idnumber[i] != 'x')
            {

                idnumbers[i] = idnumber[i] - 48;
            }
            else
            {
                idnumbers[i] = 10;
            }
        }
        for (int i = 0; i < 17; i++)
        {
            xishusum += (xishu[i] * idnumbers[i]);
        }
        if (validation[xishusum % 11] == idnumbers[17])
        {
            return true;
        }
    }
    return false;
}

void ReserveNewRecord()
{
    Record newrecord;
    cout << "请输入您的信息（输入0来返回）";
    cout << "您的姓名：" << endl;
    cin >> newrecord.name;
    if (newrecord.name == "0")
    {
        return;
    }
    cout << "您的性别（男：1， 女：0）：" << endl;
    cin >> newrecord.sex;
    cout << "您的电话号码：" << endl;
    while (true)
    {
        cin >> newrecord.phoneNumber;
        if (newrecord.phoneNumber.length() != 11 || newrecord.phoneNumber[0] != '1')
        {
            cout << "请输入正确的手机号码！" << endl;
        }
        else
        {
            break;
        }
    }
    cout << "您的身份证号：" << endl;
    while (true)
    {
        cin >> newrecord.idNumber;
        if (ValidateIDNumber(newrecord.idNumber))
        {
            break;
        }
        else
        {
            cout << "请输入正确的身份证号码！" << endl;
        }
    }
    cout << "您的单位信息：" << endl;
    cin >> newrecord.organization;
    cout << "您的车牌号：" << endl;
    cin >> newrecord.carNumber;
    cout << "您的进校理由：" << endl;
    cin >> newrecord.reason;
    cout << "您的担保人：" << endl;
    cin >> newrecord.warrantor;
    cout << "您的担保人手机号：" << endl;
    while (true)
    {
        cin >> newrecord.warrantorPhoneNumber;
        if (newrecord.warrantorPhoneNumber.length() != 11 || newrecord.warrantorPhoneNumber[0] != '1')
        {
            cout << "请输入正确的手机号码！" << endl;
        }
        else
        {
            break;
        }
    }
    cout << "您的健康码颜色：" << endl;
    cin >> newrecord.healthQRCodeColor;
    cout << "您是否来自高危区：（是：1， 否：0）" << endl;
    cin >> newrecord.visitedRiskyRegionIn14Days;
    cout << "申请进入时间" << endl;
    newrecord.estimatedEnterTime = InputTime();
    cout << "申请离开时间" << endl;
    while (true)
    {
        string newtime = InputTime();
        if (CompareTime(newrecord.actualEnterTime, newtime))
        {
            newrecord.estimatedLeaveTime = newtime;
            newrecord.expired = true;
            break;
        }
        else
        {
            cout << "离开的时间不能比进入的时间早！" << endl;
        }
    }
    newrecord.actualEnterTime = "None";
    newrecord.actualLeaveTime = "None";
    newrecord.expired = 0;
    PrintRecord(newrecord);
    records.push_back(newrecord);
}

void RegisterIn()
{
    system("cls");
    int choice;
    PrintAllActiveRecords();
    cout << "现在登记入校时间。请输入记录的序号（从0开始数）。输入-1来返回。";
    cin >> choice;
    if (choice < 0)
    {
        return;
    }
    records[choice].actualEnterTime = InputTime();
}

void RegisterOut()
{
    system("cls");
    int choice;
    PrintAllActiveRecords();
    cout << "现在登记出校时间。请输入记录的序号（从0开始数）。输入-1来返回。";
    cin >> choice;
    if (choice < 0)
    {
        return;
    }
    while (true)
    {
        string newtime = InputTime();
        if (CompareTime(records[choice].actualEnterTime, newtime))
        {
            records[choice].actualLeaveTime = newtime;
            records[choice].expired = true;
            break;
        }
        else
        {
            cout << "离开的时间不能比进入的时间早！" << endl;
        }
    }
}

void PrintMainMenu()
{
    cout << "                __        __     _                                _____        _   _  ____   _   _    ____  ___ __     __ ___  ____\n                \\ \\      / /___ | |  ___  ___   _ __ ___    ___  |_   _|___   | | | ||  _ \\ | | | |  / ___|/ _  \\ \\   / /|_ _||  _ \n                 \\ \\ /\\ / // _ \\| | / __|/ _ \\ | '_ ` _ \\  / _ \\   | | / _ \\  | |_| || | | || | | | | |   | | | |\\ \\ / /  | | | | | |\n                  \\ V  V /|  __/| || (__| (_) || | | | | ||  __/   | || (_) | |  _  || |_| || |_| | | |___| |_| | \\ V /   | | | |_| |\n                   \\_/\\_/  \\___||_| \\___|\\___/ |_| |_| |_| \\___|   |_| \\___/  |_| |_||____/  \\___/   \\____|\\___/   \\_/   |___||____/\n\n                                 __  __                                     ____               _                    _\n                                |  \\/  |  __ _  _ __    __ _   __ _   ___  / ___|  _   _  ___ | |_  ___  _ __ ___  | |\n                                | |\\/| | / _` || '_ \\  / _` | / _` | / _ \\ \\___ \\ | | | |/ __|| __|/ _ \\| '_ ` _ \\ | |\n                                | |  | || (_| || | | || (_| || (_| ||  __/  ___) || |_| |\\__ \\| |_|  __/| | | | | ||_|\n                                |_|  |_| \\__,_||_| |_| \\__,_| \\__, | \\___| |____/  \\__, ||___/ \\__|\\___||_| |_| |_|(_)\n                                                              |___/                |___/" << endl;
    cout << "主界面" << endl;
    cout << "1.预约出入校" << endl;
    cout << "2.登记入校" << endl;
    cout << "3.登记出校" << endl;
    cout << "4.已完成" << endl;
    cout << "5.保存并退出" << endl;
    cout << "6.摸鱼" << endl;
    cout << endl
         << "请输入你的选择序号" << endl;
}

void GoBack()
{
    system("pause");
    system("cls");
}

void test()
{
    string idnumber = "622722200202041012";
    cout << ValidateIDNumber(idnumber) << endl;
    PrintTitle();
    Record test;
    test.actualEnterTime = "2020-20-20_20:20";
    test.actualLeaveTime = "2020-20-20_20:20";
    test.carNumber = "浙A-99AAA";
    test.caughtCold = true;
    test.estimatedEnterTime = "2020-20-20_20:20";
    test.estimatedLeaveTime = "2020-20-20_20:20";
    test.expired = false;
    test.healthQRCodeColor = "红";
    test.idNumber = "666666666666666666";
    test.name = "欧阳锤子";
    test.organization = "杭州电子科技大学";
    test.phoneNumber = "19999999999";
    test.reason = "观看锤子科技新品发布会";
    test.sex = true;
    test.visitedRiskyRegionIn14Days = false;
    test.warrantor = "欧阳锤子";
    test.warrantorPhoneNumber = "19999999999";
    test.expired = false;
    records.push_back(test);
    boolean flag = DetectExistingData();
    if (flag)
    {
        cout << "File Exist!" << endl;
        ReadRecords();
        cout << "共计条目数量：" << (int)records.size() << endl;
    }
    else
    {
        cout << "File Does NOT Exist!" << endl;
        CreateDatabase();
        SaveRecords();
    }
    string time4test2 = "2021-02-05_09:23";
    string time4test1 = "2021-02-05_22:23";
    cout << "Testing Time Comparator" << endl;
    CompareTime(time4test1, time4test2);
    ofstream ofile;
    ofile.open(path + database_name);
    SaveRecords();
    system("pause");
    exit(0);
}

int main()
{
    // system("chcp 65001");
    int choice;
    if (DetectExistingData())
    {
        ReadRecords();
    }
    else
    {
        cout << "看起来你是第一次使用本软件，欢迎~" << endl;
    }
    while (true)
    {
        PrintMainMenu();
        cin >> choice;
        if (choice == 1)
        {
            ReserveNewRecord();
            GoBack();
        }
        else if (choice == 2)
        {
            RegisterIn();
            GoBack();
        }
        else if (choice == 3)
        {
            RegisterOut();
            GoBack();
        }
        else if (choice == 4)
        {
            PrintAllFinishedRecords();
            GoBack();
        }
        else if (choice == 5)
        {
            SaveRecords();
            break;
        }
        else if (choice == 6)
        {
            system("mode con cols=120 lines=42");
            try
            {
                snakeGame game;
            }
            catch (runtime_error &gameEnd)
            { //结束
                system("cls");
                cout << gameEnd.what() << endl;
                ShowCursor();
                system("pause");
            }
        }
    }
    system("pause");
    return 0;
}